/*
-----------------------------------------------------------------------------
 
Mogre vector class nabbed and included in the package. Original information below
 
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine) ported to C++/CLI
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2005 The OGRE Team
Also see acknowledgements in Readme.html

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.
-----------------------------------------------------------------------------
*/
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;

namespace XDL.Framework.OpenSteer
{
	//value class Quaternion;

    /** Standard 3-dimensional vector.
        @remarks
            A direction in 3D space represented as distances along the 3
            orthoganal axes (x, y, z). Note that positions, directions and
            scaling factors can be represented by a vector, depending on how
            you interpret the values.
    */
	//[Serializable]
	public class Vector3Utility
    {
        /** Returns a vector at a point half way between this and the passed
            in vector.
        */
        public static Vector3 MidPoint(Vector3 a,Vector3 b)
        {
            return new Vector3(
                ( a.X + b.X ) * 0.5f,
                ( a.Y + b.Y ) * 0.5f,
                ( a.Z + b.Z ) * 0.5f );
        }

        /// <summary>
        /// Sets this vector's components to the minimum of its own and the
        /// ones of the passed in vector.
        /// </summary>
        /// <remarks>
        /// 'Minimum' in this case means the combination of the lowest
        /// value of x, y and z from both vectors. Lowest is taken just
        /// numerically, not magnitude, so -1 &lt; 0.
        /// </remarks>
        /// <param name="floor"></param>
        /// <param name="cmp"></param>
        public static void MakeFloor(Vector3 floor, ref Vector3 cmp)
        {
            if( floor.X < cmp.X ) cmp.X = floor.X;
            if( floor.Y < cmp.Y ) cmp.Y = floor.Y;
            if( floor.Z < cmp.Z ) cmp.Z = floor.Z;
        }

        /** Sets this vector's components to the maximum of its own and the
            ones of the passed in vector.
            @remarks
                'Maximum' in this case means the combination of the highest
                value of x, y and z from both vectors. Highest is taken just
                numerically, not magnitude, so 1 > -3.
        */
        public void MakeCeil(Vector3 ceil, ref Vector3 cmp)
        {
            if (ceil.X > cmp.X) cmp.X = ceil.X;
            if (ceil.Y > cmp.Y) cmp.Y = ceil.Y;
            if (ceil.Z > cmp.Z) cmp.Z = ceil.Z;
        }

        /** Generates a vector perpendicular to this vector (eg an 'up' vector).
            @remarks
                This method will return a vector which is perpendicular to this
                vector. There are an infinite number of possibilities but this
                method will guarantee to generate one of them. If you need more
                control you should use the Quaternion class.
        */
        public static Vector3 Perpendicular(Vector3 v)
        {
            float fSquareZero = 0.000001f * 0.000001f;// 1e-06 * 1e-06;
            
            Vector3 perp = Vector3.Cross(v, Vector3.UnitX);

            // Check length
            if (perp.LengthSquared() < fSquareZero)
            {
                /* This vector is the Y axis multiplied by a scalar, so we have
                   to use another axis.
                */
                perp = Vector3.Cross(v, Vector3.UnitY);
            }

            return perp;
        }

        /** Calculates a reflection vector to the plane with the given normal .
        @remarks NB assumes 'this' is pointing AWAY FROM the plane, invert if it is not.
        */
        public static Vector3 Reflect(Vector3 v,Vector3 normal)
        {
            return v - ( 2 * Vector3.Dot(v,normal) * normal );
        }

        // special points
        public static Vector3 NEGATIVE_UNIT_X = new Vector3( -1,  0,  0 );
        public static Vector3 NEGATIVE_UNIT_Y = new Vector3(0, -1, 0);
        public static Vector3 NEGATIVE_UNIT_Z = new Vector3(0, 0, -1);
    }
}